概述
本节从 RBAC 的局限性出发,引出基于策略的权限控制(Policy-Based Access Control),介绍业界主流的 CASL 权限库。CASL 提供了比 RBAC 更细粒度的权限控制能力,支持字段级别的访问限制,且与 NestJS 生态高度契合。
RBAC 的局限性
RBAC(基于角色的访问控制)只能做到接口级别的权限控制:
用户 → 角色 → 接口权限
text
以下场景 RBAC 无法满足:
| 场景 | RBAC 能否实现 | 说明 |
|---|---|---|
| 用户只能操作自己的文章 | 不能 | RBAC 无法判断数据归属 |
| 只允许修改文章的特定字段 | 不能 | RBAC 粒度到接口,不到字段 |
| 不同状态的文章有不同的操作权限 | 不能 | RBAC 无法关联数据状态 |
| 用户只能读取部分敏感字段 | 不能 | RBAC 不关心字段级别 |
CASL 解决上述问题的方案是策略权限控制(ABAC/ACL):
用户 → 角色 → 策略 → 字段级别权限
text
CASL 库介绍
基本定位
CASL(读音 /ka-səl/)是一个同构的 JavaScript 授权库:
- 同构(Isomorphic):前端(Vue/React/Angular)和后端(Node.js)都可使用
- 授权(Authorization):专注于权限判断,不是认证
- ORM 集成:与 Prisma、Mongoose 等 ORM 无缝集成
市场占有率
CASL 在 npm 下载量上远超同类库:
| 库名 | 定位 | 下载量对比 |
|---|---|---|
| @casl/ability | 同构授权 | 最高(蓝色线) |
| access-control | ACL 实现 | 低 |
| express-acl | Express 专用 | 低 |
| acl | 基础 ACL | 低 |
安装
pnpm install @casl/ability
bash
建议锁定大版本号(当前为 v6),避免 API 变更影响项目。
CASL 核心概念
CASL 围绕四个核心概念构建:
| 概念 | 英文 | 说明 | 示例 |
|---|---|---|---|
| 操作 | Action | 用户要执行的动作 | read、update、delete |
| 主体 | Subject | 操作的目标对象 | Post、User、Comment |
| 字段 | Fields | Subject 中的具体属性 | title、content、status |
| 条件 | Conditions | 满足条件才生效 | { authorId: 1 } |
特殊关键字
| 关键字 | 含义 | 等价于 |
|---|---|---|
manage | 任意操作 | 所有 action 的集合 |
all | 任意主体 | 所有 subject 的集合 |
defineAbility 基础用法
import { defineAbility } from '@casl/ability';
const ability = defineAbility((can, cannot) => {
can('manage', 'all'); // 允许操作所有资源
cannot('delete', 'User'); // 禁止删除用户
});
typescript
can 和 cannot 是语义化的权限声明方法,分别表示"允许"和"禁止"。
权限判断
ability.can('read', 'Post'); // true - 可以读取文章
ability.can('update', 'Post'); // true - 可以更新文章(manage 包含 update)
ability.can('delete', 'User'); // false - 不可以删除用户
typescript
与 RBAC 手写判断逻辑相比,CASL 的优势:
- 语义化:
can/cannot直接表达权限意图,代码可读性极高 - 声明式:权限规则集中定义,不散落在各处
- 可序列化:权限规则可存储到数据库,实现动态权限
字段级别控制
CASL 支持对 Subject 的特定字段设置操作权限:
import { defineAbility } from '@casl/ability';
const ability = defineAbility((can, cannot) => {
can('read', 'Article'); // 可以读取文章
can('update', 'Article', ['title', 'content'], // 只能更新 title 和 content
{ authorId: 1 }); // 且文章作者必须是当前用户
});
typescript
这种精细度的控制在 RBAC 中是不可能实现的,CASL 通过将操作 + 主体 + 字段 + 条件组合成一个完整的权限规则来达成。
NestJS 官方推荐
NestJS 官方文档中明确推荐 CASL 作为权限控制方案:
- 官方提供了完整的 CASL 集成指南
- 基于 Guard + Decorator 的实现模式与 NestJS 架构一致
- 社区成熟,问题容易排查
Quokka.js 开发辅助
本节使用 Quokka.js 作为代码实验工具,可在 VS Code 中实时查看 TypeScript 执行结果:
- 安装 VS Code 扩展:搜索
Quokka - 通过命令面板(
Cmd+Shift+P)创建新文件:Quokka: New JavaScript File或TypeScript File - 输入代码后,每行末尾实时显示执行结果
学习新库时推荐使用 Quokka 进行快速验证,避免频繁启动完整项目。
关键知识点总结
| 知识点 | 说明 |
|---|---|
| RBAC 局限性 | 只能控制接口级别,无法做到字段/数据归属级别 |
| CASL 核心概念 | Action + Subject + Fields + Conditions |
manage / all | 特殊关键字,代表所有操作和所有主体 |
| 字段级控制 | can('update', 'Article', ['title']) 限制可操作的字段 |
| 同构能力 | 前后端可共享同一套权限规则 |
↑